﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.OleDb;

namespace Marmat.Data
{
    public class SQLCommand : IDisposable
    {


        /* TODO ERROR: Skipped RegionDirectiveTrivia */
        public SQLCommand()
        {
        }

        public SQLCommand(string ConnectionName)
        {
            this.ConnectionName = ConnectionName;
        }

        public SQLCommand(BaseConnection Connection)
        {
            this.m_Connection = Connection;
        }

        public SQLCommand(string ConnectionName, string CommandText)
        {
            this.ConnectionName = ConnectionName;
            this.CommandText = CommandText;
        }

        public SQLCommand(BaseConnection Connection, string CommandText)
        {
            this.m_Connection = Connection;
            this.CommandText = CommandText;
        }

        /* TODO ERROR: Skipped EndRegionDirectiveTrivia */
        /* TODO ERROR: Skipped RegionDirectiveTrivia */
        private string _ConnectionName;
        /// <summary>
        /// 获取或设置数据源名称
        /// </summary>
        /// <remarks></remarks>
        public string ConnectionName
        {
            get
            {
                return this._ConnectionName;
            }

            set
            {
                this._ConnectionName = value;
            }
        }

        /// <summary>
        /// SQL 语句或存储过程的参数。 默认值为空集合。
        /// </summary>
        public Dictionary<string, object> Parameters
        {
            get
            {
                if (this._parameters is null)
                    this._parameters = new Dictionary<string, object>();
                return this._parameters;
            }
        }

        private Dictionary<string, object> _parameters;
        private BaseConnection m_Connection;

        internal BaseConnection Connection
        {
            get
            {
                if (this.m_Connection is null)
                {
                    if (!string.IsNullOrEmpty(this.ConnectionName) && Connections.Contains(this.ConnectionName))
                        this.m_Connection = Connections.Item(this.ConnectionName);
                    else if (string.IsNullOrEmpty(this.ConnectionName) && Connections.Count > 0)
                        return Connections.Default;
                }
                return this.m_Connection;
            }
        }

        private string _commandText;

        /// <summary>
        /// 获取或设置SQL命令
        /// </summary>
        public string CommandText
        {
            get => this._commandText;
            set => this._commandText = value;
        }

        private int _commandTimeOut = 30;
        /// <summary>
        /// 获取或设置在终止执行命令的尝试并生成错误之前的等待时间。
        /// </summary>
        /// <returns>等待命令执行的时间（以秒为单位）。默认值为 30 秒。</returns>
        public int CommandTimeOut
        {
            get => this._commandTimeOut;
            set => this._commandTimeOut = value;
        }

        /// <summary>
        /// 执行操作后是否自动关闭数据源的连接。
        /// </summary>
        public bool AutoClose { get; set; } = true;

        /// <summary>
        /// 用于执行返回单个值的命令,并将结果转换为指定的类型。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public T ExecuteScalar<T>()
        {
            return (T)Convert.ChangeType(this.ExecuteScalar(), typeof(T));
        }


        /// <summary>
        /// 用于执行返回单个值的命令
        /// </summary>
        /// <returns></returns>
        public virtual object ExecuteScalar()
        {
            object obj = null;
            if (this.Connection is null)
                throw new NullReferenceException("未指定数据源。");

            this.Connection.Open();
            var options = new ConnectionExecuteOptions(this.CommandText, this.Parameters);
            options.CommandTimeOut = this.CommandTimeOut;
            obj = this.Connection.ExecuteScalar(options);
            if (this.AutoClose)
                this.Connection.Close();
            return obj;
        }

        /// <summary>
        /// 执行 SQL 语句并返回受影响的行数。
        /// </summary>
        /// <remarks></remarks>
        public virtual int ExecuteNonQuery()
        {
            if (this.Connection is null)
                throw new NullReferenceException("未指定数据源。");
            this.Connection.Open();
            var options = new ConnectionExecuteOptions(this.CommandText, this.Parameters);
            options.CommandTimeOut = this.CommandTimeOut;
            int obj = this.Connection.ExecuteNonQuery(options);
            if (this.AutoClose)
                this.Connection.Close();
            return obj;
        }

        /// <summary>
        /// 用于从后台提取数据生成一个临时的DataTable，而这个DataTable只存在于代码的运行过程中，不会以表的形式呈现给用户
        /// </summary>
        /// <returns></returns>
        /// <remarks></remarks>
        public virtual DataTable ExecuteReader()
        {
            DataTable dt;
            if (this.Connection is null)
                throw new NullReferenceException("未指定数据源。");
            var options = new ConnectionExecuteOptions(this.CommandText, this.Parameters);
            options.CommandTimeOut = this.CommandTimeOut;
            dt = this.Connection.ExecuteReader(options);
            if (this.AutoClose)
                this.Connection.Close();
            return dt;
        }

        ///// <summary>
        ///// 用于从后台提取数据生成一个临时的DataTable，而这个DataTable只存在于代码的运行过程中，不会以表的形式呈现给用户
        ///// </summary>
        ///// <returns></returns>
        ///// <remarks></remarks>
        //public int Fill(DataTable dataTable)
        //{
        //    var Result = default(int);
        //    if (this.Connection is object)
        //    {
        //        switch (this.Connection.SourceType)
        //        {
        //            case SourceType.Access:
        //                {
        //                    using (var SqlDataAdapter = new OleDbDataAdapter(this.CommandText, this.Connection))
        //                    {
        //                        SqlDataAdapter.SelectCommand.CommandTimeout = this.CommandTimeOut;
        //                        foreach (string Item in this.Parameters.Keys)
        //                            SqlDataAdapter.SelectCommand.Parameters.AddWithValue(Item, this.Parameters[Item]);
        //                        Result = SqlDataAdapter.Fill(dataTable);
        //                    }

        //                    break;
        //                }

        //            case SourceType.SQLServer:
        //                {
        //                    using (var SqlDataAdapter = new System.Data.SqlClient.SqlDataAdapter(this.CommandText, this.Connection))
        //                    {
        //                        SqlDataAdapter.SelectCommand.CommandTimeout = this.CommandTimeOut;
        //                        foreach (string Item in this.Parameters.Keys)
        //                            SqlDataAdapter.SelectCommand.Parameters.AddWithValue(Item, this.Parameters[Item]);
        //                        Result = SqlDataAdapter.Fill(dataTable);
        //                    }

        //                    break;
        //                }
        //                // Case SourceType.MySQL
        //                // Using SqlDataAdapter As New MySql.Data.MySqlClient.MySqlDataAdapter(Me.CommandText, Me.Connection.GetConnection(Of MySql.Data.MySqlClient.MySqlConnection))
        //                // SqlDataAdapter.SelectCommand.CommandTimeout = CommandTimeOut
        //                // Result = SqlDataAdapter.Fill(DataTable)
        //                // End Using
        //                // Case SourceType.Oracle
        //                // Throw New Exception("Oracle的ExecuteReader方法尚未实现。")
        //        }
        //    }
        //    else
        //    {
        //        throw new Exception("未指定数据源。");
        //    }

        //    return Result;
        //}

        // ''' <summary>
        // ''' 根据指定的 System.Data.SchemaType 配置指定 System.Data.DataTable 的架构。
        // ''' </summary>
        // ''' <param name="CommandText"></param>
        // ''' <returns></returns>
        // ''' <remarks></remarks>
        // Function GetSchema(ByVal CommandText As String) As DataTable
        // Dim dt As New System.Data.DataTable
        // Me.FillSchema(dt, SchemaType.Mapped)
        // End Function

        ///// <summary>
        ///// 根据指定的 System.Data.SchemaType 配置指定 System.Data.DataTable 的架构。
        ///// </summary>
        ///// <param name="dataTable">要用数据源中的架构填充的 System.Data.DataTable。</param>
        ///// <param name="schemaType">System.Data.SchemaType 值之一。</param>
        ///// <returns>包含从数据源返回的架构信息的 System.Data.DataTable。</returns>
        //public DataTable FillSchema(DataTable dataTable, SchemaType schemaType)
        //{
        //    if (this.Connection is object)
        //    {
        //        DataTable dt = null;
        //        switch (this.Connection.SourceType)
        //        {
        //            case SourceType.Access:
        //                {
        //                    using (var SqlDataAdapter = new OleDbDataAdapter(this.CommandText, this.Connection.GetConnection<OleDbConnection>()))
        //                    {
        //                        foreach (string Item in this.Parameters.Keys)
        //                            SqlDataAdapter.SelectCommand.Parameters.AddWithValue(Item, this.Parameters[Item]);
        //                        dt = SqlDataAdapter.FillSchema(dataTable, schemaType);
        //                    }

        //                    break;
        //                }

        //            case SourceType.SQLServer:
        //                {
        //                    using (var SqlDataAdapter = new System.Data.SqlClient.SqlDataAdapter(this.CommandText, this.Connection.GetConnection<System.Data.SqlClient.SqlConnection>()))
        //                    {
        //                        foreach (string Item in this.Parameters.Keys)
        //                            SqlDataAdapter.SelectCommand.Parameters.AddWithValue(Item, this.Parameters[Item]);
        //                        dt = SqlDataAdapter.FillSchema(dataTable, schemaType);
        //                    }

        //                    break;
        //                }
        //            // Case SourceType.MySQL
        //            // Using SqlDataAdapter As New MySql.Data.MySqlClient.MySqlDataAdapter(Me.CommandText, Me.Connection.GetConnection(Of MySql.Data.MySqlClient.MySqlConnection))
        //            // dt = SqlDataAdapter.FillSchema(dataTable, schemaType)
        //            // End Using
        //            case SourceType.Oracle:
        //                {
        //                    throw new Exception("Oracle的FillSchema方法尚未实现。");
        //                    break;
        //                }
        //        }

        //        return dt;
        //    }
        //    else
        //    {
        //        throw new Exception("未指定数据源。");
        //    }
        //}

        /// <summary>
        /// 从指定的列中提取不重复的值，用符号"|"将这些值连接成一个字符串，并返回这个字符串。
        /// </summary>
        /// <param name="TableName"></param>
        /// <param name="ColName"></param>
        /// <returns></returns>
        /// <remarks></remarks>
        public List<string> GetValues(string TableName, string ColName)
        {
            return this.GetValues(TableName, ColName, null, null);
        }

        /// <summary>
        /// 从指定的列中提取不重复的值，用符号"|"将这些值连接成一个字符串，并返回这个字符串。
        /// </summary>
        /// <param name="TableName"></param>
        /// <param name="ColName"></param>
        /// <param name="Filter"></param>
        /// <returns></returns>
        /// <remarks></remarks>
        public List<string> GetValues(string TableName, string ColName, string Filter)
        {
            return this.GetValues(TableName, ColName, Filter, null);
        }

        /// <summary>
        /// 从指定的列中提取不重复的值，用符号"|"将这些值连接成一个字符串，并返回这个字符串。
        /// </summary>
        /// <param name="TableName"></param>
        /// <param name="ColName"></param>
        /// <param name="Filter"></param>
        /// <param name="Sort"></param>
        /// <returns></returns>
        /// <remarks></remarks>
        public List<string> GetValues(string TableName, string ColName, string Filter, string Sort)
        {
            var List = new List<string>();
            if (!string.IsNullOrEmpty(Filter) && !string.IsNullOrEmpty(Sort))
            {
                Filter = " WHERE " + Filter + " ORDER BY " + Sort;
            }
            else if (!string.IsNullOrEmpty(Filter))
            {
                Filter = " WHERE " + Filter;
            }
            else if (!string.IsNullOrEmpty(Sort))
            {
                Filter = " ORDER BY " + Sort;
            }

            this.CommandText = string.Format("SELECT {0} FROM [{1}]", ColName, TableName) + Filter;
            var dt = this.ExecuteReader();
            foreach (DataRow dr in dt.Rows)
            {
                if (List.Contains(dr[0].ToString()) == false)
                {
                    List.Add(dr[0].ToString());
                }
            }

            return List;
        }

        /// <summary>
        /// 从指定的列中提取不重复的值，用符号"|"将这些值连接成一个字符串，并返回这个字符串。
        /// </summary>
        /// <param name="TableName"></param>
        /// <param name="ColName"></param>
        /// <returns></returns>
        /// <remarks></remarks>
        public string GetComboListString(string TableName, string ColName)
        {
            return this.GetComboListString(TableName, ColName, null, null);
        }

        /// <summary>
        /// 从指定的列中提取不重复的值，用符号"|"将这些值连接成一个字符串，并返回这个字符串。
        /// </summary>
        /// <param name="TableName"></param>
        /// <param name="ColName"></param>
        /// <param name="Filter"></param>
        /// <returns></returns>
        /// <remarks></remarks>
        public string GetComboListString(string TableName, string ColName, string Filter)
        {
            return this.GetComboListString(TableName, ColName, Filter, null);
        }

        /// <summary>
        /// 从指定的列中提取不重复的值，用符号"|"将这些值连接成一个字符串，并返回这个字符串。
        /// </summary>
        /// <param name="TableName"></param>
        /// <param name="ColName"></param>
        /// <param name="Filter"></param>
        /// <param name="Sort"></param>
        /// <returns></returns>
        /// <remarks></remarks>
        public string GetComboListString(string TableName, string ColName, string Filter, string Sort)
        {
            var txt = new System.Text.StringBuilder();
            var List = this.GetValues(TableName, ColName, Filter, Sort);
            foreach (string Str in List)
                txt.Append("|" + Str);
            if (txt.Length > 0)
            {
                txt.Remove(0, 1);
            }

            return txt.ToString();
        }

        /// <summary>
        /// 获取自动编号生成的值
        /// </summary>
        /// <param name="Name">编号规则的名称</param>
        /// <param name="TableName">编号所对应的表名，用于检测生成的编号是否有重复</param>
        /// <param name="ColName">编号所对应的列名，用于检测生成的编号是否有重复</param>
        /// <param name="Id">编号表所对应的条件，通常用于多帐套</param>
        /// <param name="Filter">编号所对应的条件，用于检测生成的编号在次条件下是否有重复，通常用于多帐套</param>
        /// <returns></returns>
        /// <remarks></remarks>
        public string SerialNumber(string Name, string TableName, string ColName, string Id, string Filter = null)
        {
            string txt = Properties.Resources.自动编号;
            Name = Name.Replace("'", "''");
            Id = Id.Replace("'", "''");
            TableName = TableName.Replace("'", null);
            ColName = ColName.Replace("'", null);
            this.CommandText = string.Format(txt, Name, Id, TableName, ColName, !string.IsNullOrEmpty(Filter) ? " AND " : "", Filter);
            string obj = Convert.ToString(this.ExecuteScalar());
            return obj;
        }
        /* TODO ERROR: Skipped EndRegionDirectiveTrivia */
        /* TODO ERROR: Skipped RegionDirectiveTrivia */
        private bool disposedValue; // 检测冗余的调用

        // IDisposable
        protected virtual void Dispose(bool disposing)
        {
            if (!this.disposedValue)
            {
                if (disposing)
                {
                    // TODO:  释放托管状态(托管对象)。
                }

                // TODO:  释放非托管资源(非托管对象)并重写下面的 Finalize()。
                // TODO:  将大型字段设置为 null。
            }

            this.disposedValue = true;
        }

        // TODO:  仅当上面的 Dispose(ByVal disposing As Boolean)具有释放非托管资源的代码时重写 Finalize()。
        // Protected Overrides Sub Finalize()
        // ' 不要更改此代码。    请将清理代码放入上面的 Dispose(ByVal disposing As Boolean)中。
        // Dispose(False)
        // MyBase.Finalize()
        // End Sub

        // Visual Basic 添加此代码是为了正确实现可处置模式。
        public void Dispose()
        {
            // 不要更改此代码。    请将清理代码放入上面的 Dispose (disposing As Boolean)中。
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }
        /* TODO ERROR: Skipped EndRegionDirectiveTrivia */
    }
}